/******************************************************************************************
文件名：stream.c
作者：狼狼    版本：V1.0    日期：2020.11.23
文件描述：
    程序中有关图像采集部分的处理。
版本信息：
    STv7-t版本，为Loice Slave修改。
历史修改记录：
1. 2021-9-9:V1.0 狼狼
从STv7-t存档中取出，为Loice Slave功能做修改。
2. 2022-5-11:V1.0 狼狼
代码公开。
******************************************************************************************/
//                                              ↓
//+------------------------------------------------------------------------------------------+
//|                                          文件说明
//+------------------------------------------------------------------------------------------+
//|      程序在博云IPC成品板上运行，基于Hi3518EV200。
//+------------------------------------------------------------------------------------------+
//|                                         头文件包含
//+------------------------------------------------------------------------------------------+
/*|*/#include <stdio.h>
/*|*/#include <stdbool.h>
/*|*/#include <stdint.h>
/*|*/#include <stdlib.h>
/*|*/#include <string.h>
/*|*/#include <unistd.h>
/*|*/#include <pthread.h>
/*|*/#include <signal.h>
/*|*/#include <fcntl.h>
/*|*/#include <sys/types.h>
/*|*/#include <sys/stat.h>
/*|*/#include <sys/ioctl.h>
/*|*/#include <sys/poll.h>
/*|*/#include <sys/time.h>
/*|*/
/*|*/#include "stream.h"
/*|*/#include "project_debug.h"
//+------------------------------------------------------------------------------------------+
//|                                          宏定义
//+------------------------------------------------------------------------------------------+
/*|*/ #define SYS_ALIGN_WIDTH 64//对齐宽度
//+------------------------------------------------------------------------------------------+
//|                                          全局变量
//+------------------------------------------------------------------------------------------+
/*|*/static pthread_t gs_IspPid = 0;
/*|*/static HI_BOOL gbIspInited = HI_FALSE;
//|    ----------------------------------------
//|    视频流处理线程描述符
//|    ----------------------------------------
/*|*/static pthread_t pthread_t_stream;
//|    ----------------------------------------
//|    用于指示采集线程是否存在
//|    ----------------------------------------
/*|*/static int flag_stream_start=0;
//|    ----------------------------------------
//|    采集线程运行许可
//|    ----------------------------------------
/*|*/static bool flag_stream_enable=0;
//|
//|    ----------------------------------------
//|    码流处理回调
//|    ----------------------------------------
/*|*/static void (*pstream_proc)(uint8_t *pstream, int stream_len);
//|
/*|*/static VI_DEV_ATTR_S DEV_ATTR_OV9732_DC_720P=
/*|*/{
/*|*/    /*连接模式*/
/*|*/    VI_MODE_DIGITAL_CAMERA,
/*|*/    /*多重模式*/
/*|*/    VI_WORK_MODE_1Multiplex,
/*|*/    /* r_mask    g_mask    b_mask*/
/*|*/    {0x3FF0000,    0x0},
/*|*/    /*渐进式或交错式*/
/*|*/    VI_SCAN_PROGRESSIVE,//渐进式
/*|*/    /*AdChnId*/
/*|*/    {-1, -1, -1, -1},
/*|*/    /*支持的数据序列，仅支持YUV*/
/*|*/    VI_INPUT_DATA_YUYV,
/*|*/    /*同步信息*/
/*|*/    {
/*|*/        /*port_vsync   port_vsync_neg    port_hsync    port_hsync_neg  */
/*|*/        VI_VSYNC_FIELD, VI_VSYNC_NEG_HIGH, VI_HSYNC_VALID_SINGNAL,VI_HSYNC_NEG_HIGH,VI_VSYNC_VALID_SINGAL,VI_VSYNC_VALID_NEG_HIGH,
/*|*/        /*hsync_hfb    hsync_act   hsync_hhb*/
/*|*/        {370,            1280,        0,
/*|*/        /*vsync0_vhb   vsync0_act  vsync0_hhb*/
/*|*/         6,            720,        6,
/*|*/        /*vsync1_vhb   vsync1_act  vsync1_hhb*/
/*|*/         0,            0,            0}
/*|*/    },
/*|*/    /*使用内置ISP*/
/*|*/    VI_PATH_ISP,
/*|*/    /*输入数据类型*/
/*|*/    VI_DATA_TYPE_RGB,
/*|*/    /*数据反转*/
/*|*/    HI_FALSE,
/*|*/    {0, 0, 1280, 720}
/*|*/};
//|    ----------------------------------------
//|    该结构体用于初始化MIPI Rx的工作模式，
//|    参见《HiMPP MIPI使用指南》P20、P37。
//|    ----------------------------------------
/*|*/combo_dev_attr_t MIPI_CMOS3V3_ATTR=
/*|*/{
/*|*/    .input_mode=INPUT_MODE_CMOS_33V,
/*|*/    {
/*|*/        
/*|*/    }
/*|*/};
//|
/*|*/struct L_Stream_Para
/*|*/{
/*|*/    unsigned int width;//设置的最终输出宽
/*|*/    unsigned int height;//设置的最终输出高
/*|*/    unsigned int framerate;//设置的编码帧率
/*|*/    //设置的曝光时间
/*|*/}H264Para =
/*|*/{
/*|*/    .width     = 1280,
/*|*/    .height    = 720,
/*|*/    .framerate = 30,
/*|*/};
//+------------------------------------------------------------------------------------------+
//|  函数名称：isp_run_process
//|  功能描述：调用MPP中的ISP运行函数
//|  参数说明：无
//|  返回值说明：无
//|  备注：HI_MPI_ISP_Run为阻塞接口，故需创建线程执行
//+------------------------------------------------------------------------------------------+
static HI_VOID* isp_run_process(HI_VOID *p)
{
    HI_MPI_ISP_Run(0);
    return HI_NULL;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：stream_process
//|  功能描述：编码线程
//|  参数说明：无
//|  返回值说明：无
//|  备注：
//+------------------------------------------------------------------------------------------+
static void* stream_process(void *p)
{
    HI_S32 s32Ret=HI_SUCCESS;
    
    /* 步骤一：初始化系统变量 */
    VB_CONF_S stVbConf;//缓存池参数结构体
    memset(&stVbConf, 0, sizeof(VB_CONF_S));
    stVbConf.u32MaxPoolCnt = 128;//3518默认值128
    HI_U32 u32BlkSize;
    HI_U32 u32VbSize;
    HI_U32 u32HeaderSize;
    //******************************************
    //PIXEL_FORMAT_YUV_SEMIPLANAR_420:1.5
    //PIXEL_FORMAT_YUV_SEMIPLANAR_422:2
    //******************************************
    u32VbSize = CEILING_2_POWER(1280, SYS_ALIGN_WIDTH) * CEILING_2_POWER(720, SYS_ALIGN_WIDTH) * 1.5;
    VB_PIC_HEADER_SIZE(1280, 720, PIXEL_FORMAT_YUV_SEMIPLANAR_420, u32HeaderSize);
    u32BlkSize=u32VbSize+u32HeaderSize;
    stVbConf.astCommPool[0].u32BlkSize=u32BlkSize;
    stVbConf.astCommPool[0].u32BlkCnt=4;//例程中，针对hi3518ev200，该值为4
    
    /* 步骤二：MPP系统初始化 */
    HI_MPI_SYS_Exit();
    HI_MPI_VB_Exit();
    MPP_SYS_CONF_S stSysConf={0};
    s32Ret=HI_MPI_VB_SetConf(&stVbConf);
    if(HI_SUCCESS!=s32Ret)
    {
        OUTPUT("Set VideoBlock config failed!\n");
        goto END_0;
    }
    s32Ret=HI_MPI_VB_Init();
    if(HI_SUCCESS!=s32Ret)
    {
        OUTPUT("Init VideoBlock failed!\n");
        goto END_0;
    }
    stSysConf.u32AlignWidth=SYS_ALIGN_WIDTH;
    s32Ret=HI_MPI_SYS_SetConf(&stSysConf);
    if(HI_SUCCESS!=s32Ret)
    {
        OUTPUT("Set System config failed\n");
        goto END_0;
    }
    s32Ret=HI_MPI_SYS_Init();
    if(HI_SUCCESS!=s32Ret)
    {
        OUTPUT("Init MPI System failed!\n");
        goto END_0;
    }
    
    /* 步骤三：启动VI设备，选择捕获通道 */
    WDR_MODE_E enWDRMode=WDR_MODE_NONE;
    HI_S32 mipifd;
    VI_DEV ViDev=0;//Hi3518EV200仅有一路VI设备
    VI_CHN ViChn=0;//Hi3518EV200仅有一个物理通道
    //--1--配置MIPI
    mipifd=open("/dev/hi_mipi",O_RDWR);
    if(mipifd<0)
    {
        OUTPUT("Open HI-MIPI device failed!\n");
        goto END_1;
    }
    if(ioctl(mipifd, HI_MIPI_SET_DEV_ATTR, &MIPI_CMOS3V3_ATTR))
    {
        OUTPUT("Set MIPI Attributes failed!\n");
        close(mipifd);
        goto END_1;
    }
    close(mipifd);
    //--2--配置传感器和ISP（包括宽动态模式）
    s32Ret=sensor_register_callback();//1.传感器注册回调函数
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("sensor_register_callback failed with %#x!\n", s32Ret);
    }
    
    ALG_LIB_S stLib;
    ISP_DEV IspDev=0;
    stLib.s32Id=0;
    strcpy(stLib.acLibName,HI_AE_LIB_NAME);
    s32Ret=HI_MPI_AE_Register(IspDev, &stLib);//2.注册海思AE库
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("HI_MPI_AE_Register failed!\n");
    }
    
    stLib.s32Id=0;
    strcpy(stLib.acLibName, HI_AWB_LIB_NAME);
    s32Ret=HI_MPI_AWB_Register(IspDev, &stLib);//3.注册海思AWB库
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("HI_MPI_AWB_Register failed!\n");
    }
    
    stLib.s32Id=0;
    strcpy(stLib.acLibName, HI_AF_LIB_NAME);
    s32Ret=HI_MPI_AF_Register(IspDev, &stLib);//4.注册海思AF库
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("HI_MPI_AF_Register failed!\n");
    }
    
    s32Ret=HI_MPI_ISP_MemInit(IspDev);//5.ISP存储初始化
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("HI_MPI_ISP_Init failed!\n");
    }
    
    ISP_WDR_MODE_S stWdrMode;
    stWdrMode.enWDRMode=enWDRMode;
    s32Ret=HI_MPI_ISP_SetWDRMode(IspDev, &stWdrMode);//6.ISP设置宽动态模式
    if(HI_SUCCESS!=s32Ret)
    {
        OUTPUT("Start ISP WDR failed!\n");
    }
    
    ISP_PUB_ATTR_S stPubAttr;
    stPubAttr.enBayer              =BAYER_BGGR;//Bayer图像RGB排列格式
    stPubAttr.f32FrameRate         =30;
    stPubAttr.stWndRect.s32X       =0;
    stPubAttr.stWndRect.s32Y       =0;
    stPubAttr.stWndRect.u32Width   =1280;
    stPubAttr.stWndRect.u32Height  =720;
    s32Ret=HI_MPI_ISP_SetPubAttr(IspDev, &stPubAttr);//7.ISP设置Pub属性
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("HI_MPI_ISP_SetPubAttr failed with %#x!\n", s32Ret);
    }
    
    s32Ret=HI_MPI_ISP_Init(IspDev);//8.ISP初始化
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("HI_MPI_ISP_Init failed! %x\n",s32Ret);
    }
    
    gbIspInited=HI_TRUE;//置ISP成功初始化标志位
    //--3--启动ISP线程
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setstacksize(&attr,4096 * 1024);
    if(0!=pthread_create(&gs_IspPid,&attr,(void*(*)(void*))isp_run_process,NULL))
    {
        OUTPUT("create isp running thread failed!\n");
        pthread_attr_destroy(&attr);
        goto END_1;
    }
    usleep(1000);
    pthread_attr_destroy(&attr);
    //--4--配置&启动视频输入捕获设备
    HI_S32 s32IspDev=0;//ISP设备0
    VI_DEV_ATTR_S stViDevAttr;
    VI_WDR_ATTR_S stWdrAttr;
    memset(&stViDevAttr,0,sizeof(stViDevAttr));
    memcpy(&stViDevAttr,&DEV_ATTR_OV9732_DC_720P,sizeof(stViDevAttr));
    stViDevAttr.stDevRect.s32X=0;
    stViDevAttr.stDevRect.s32Y=0;
    stViDevAttr.stDevRect.u32Width=1280;
    stViDevAttr.stDevRect.u32Height=720;
    s32Ret=HI_MPI_VI_SetDevAttr(ViDev, &stViDevAttr);
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("Set Device Attributes failed!\n");
        goto END_1;
    }
    s32Ret=HI_MPI_ISP_GetWDRMode(s32IspDev, &stWdrMode);
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("Get WDR Mode failed!\n");
        goto END_1;
    }
    stWdrAttr.enWDRMode=stWdrMode.enWDRMode;
    stWdrAttr.bCompress=HI_FALSE;
    s32Ret=HI_MPI_VI_SetWDRAttr(ViDev, &stWdrAttr);
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("Set VI WDR Attributes failed!\n");
        goto END_1;
    }
    s32Ret=HI_MPI_VI_EnableDev(ViDev);
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("Enable VI Device failed!\n");
        goto END_1;
    }
    //--5--配置&启动视频输入捕获设备的传输通道
    RECT_S stCapRect;
    stCapRect.s32X=0;
    stCapRect.s32Y=0;
    stCapRect.u32Width=1280;
    stCapRect.u32Height=720;
    VI_CHN_ATTR_S stChnAttr;
    memcpy(&stChnAttr.stCapRect, &stCapRect, sizeof(RECT_S));
    stChnAttr.enCapSel=VI_CAPSEL_BOTH;
    stChnAttr.stDestSize.u32Width=stCapRect.u32Width;
    stChnAttr.stDestSize.u32Height=stCapRect.u32Height;
    stChnAttr.enPixFormat=PIXEL_FORMAT_YUV_SEMIPLANAR_420;//像素格式——YUC420或YUV422
    stChnAttr.s32SrcFrameRate=-1;
    stChnAttr.s32DstFrameRate=-1;
    stChnAttr.enCompressMode=COMPRESS_MODE_NONE;//不压缩
    stChnAttr.bMirror=HI_FALSE;//不镜像
    stChnAttr.bFlip=HI_FALSE;//不翻转
    s32Ret=HI_MPI_VI_SetChnAttr(ViChn, &stChnAttr);
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("Set VI Channel Attributes failed!\n");
        goto END_1;
    }
    s32Ret=HI_MPI_VI_EnableChn(ViChn);//使能VI通道
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("Enable VI Channel failed!\n");
        goto END_1;
    }
    
    /* 步骤四：启动VPSS并执行VI-VPSS绑定 */
    VPSS_GRP_ATTR_S stVpssGrpAttr;
    stVpssGrpAttr.u32MaxW=1280;
    stVpssGrpAttr.u32MaxH=720;
    stVpssGrpAttr.bIeEn=HI_FALSE;
    stVpssGrpAttr.bNrEn=HI_TRUE;
    stVpssGrpAttr.bHistEn=HI_FALSE;
    stVpssGrpAttr.bDciEn=HI_FALSE;//VPSS组属性——DCI使能
    stVpssGrpAttr.enDieMode=VPSS_DIE_MODE_NODIE;//VPSS组属性——DIE模式
    stVpssGrpAttr.enPixFmt=PIXEL_FORMAT_YUV_SEMIPLANAR_420;//VPSS组属性——像素格式——YUV420
    //创建VPSS组
    VPSS_GRP VpssGrp=0;
    s32Ret=HI_MPI_VPSS_CreateGrp(VpssGrp,&stVpssGrpAttr);
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("HI_MPI_VPSS_CreateGrp failed with %#x!\n", s32Ret);
        goto END_2;
    }
    VPSS_NR_PARAM_U unNrParam={{0}};//VPSS3DNR参数存放变量
    s32Ret=HI_MPI_VPSS_GetNRParam(VpssGrp, &unNrParam);//获取VPSS-3DNR参数
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("failed with %#x!\n", s32Ret);
        goto END_2;
    }
    s32Ret=HI_MPI_VPSS_SetNRParam(VpssGrp, &unNrParam);//设置VPSS-3DNR参数
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("failed with %#x!\n", s32Ret);
        goto END_2;
    }
    s32Ret=HI_MPI_VPSS_StartGrp(VpssGrp);
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("Start VPSS Group failed with %#x\n", s32Ret);
        goto END_2;
    }

    //VI-VPSS绑定
    MPP_CHN_S stSrcChn;
    MPP_CHN_S stDestChn;
    stSrcChn.enModId=HI_ID_VIU;
    stSrcChn.s32DevId=0;
    stSrcChn.s32ChnId=0;
    stDestChn.enModId=HI_ID_VPSS;
    stDestChn.s32DevId=VpssGrp;
    stDestChn.s32ChnId=0;
    s32Ret=HI_MPI_SYS_Bind(&stSrcChn, &stDestChn);
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("HI_MPI_SYS_Bind failed with %#x!\n", s32Ret);
        goto END_3;
    }
    VpssGrp=0;
    VPSS_CHN VpssChn=0;//当前设置的VPSS通道0
    VPSS_CHN_MODE_S stVpssChnMode;
    stVpssChnMode.enChnMode     =VPSS_CHN_MODE_USER;
    stVpssChnMode.bDouble       =HI_FALSE;
    stVpssChnMode.enPixelFormat =PIXEL_FORMAT_YUV_SEMIPLANAR_420;
    stVpssChnMode.u32Width      =1280;
    stVpssChnMode.u32Height     =720;
    stVpssChnMode.enCompressMode=COMPRESS_MODE_NONE;//无缩放
    VPSS_CHN_ATTR_S stVpssChnAttr;
    memset(&stVpssChnAttr, 0, sizeof(stVpssChnAttr));
    stVpssChnAttr.s32SrcFrameRate=-1;
    stVpssChnAttr.s32DstFrameRate=-1;
    s32Ret=HI_MPI_VPSS_SetChnAttr(VpssGrp, VpssChn, &stVpssChnAttr);
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("Set VPSS Channel Attributes failed!\n");
        goto END_3;
    }
    s32Ret=HI_MPI_VPSS_SetChnMode(VpssGrp, VpssChn,&stVpssChnMode);
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("Set VPSS Channel Mode failed!\n");
        goto END_3;
    }
    s32Ret=HI_MPI_VPSS_EnableChn(VpssGrp, VpssChn);
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("Enable VPSS Channel failed!\n");
        goto END_3;
    }
    
    /* 步骤五：VENC创建和VI-VENC绑定 */
    VENC_PARAM_MOD_S H264streampara = {0};
    H264streampara.enVencModType                       = MODTYPE_H264E;
    HI_MPI_VENC_GetModParam(&H264streampara);
    H264streampara.stH264eModParam.u32OneStreamBuffer  = 1;//设置单包模式
    H264streampara.stH264eModParam.u32H264eVBSource    = 1;//使用私有VB
    HI_MPI_VENC_SetModParam(&H264streampara);
    
    VENC_CHN VencChn=0;//Venc通道号0
    PAYLOAD_TYPE_E enPayLoad=PT_H264;   //选择编码方式——H264，更换编码要同时更换后面的设置参数
    VENC_CHN_ATTR_S stVencChnAttr;      //VENC通道属性参数结构体
    VENC_ATTR_H264_S stH264Attr;        //H264属性参数结构体
    VENC_ATTR_H264_CBR_S stH264Cbr;     //H264-CBR码率控制参数结构体
    HI_U32 u32Profile=0;                //0: baseline; 1:MP; 2:HP;3:Svc_t

    stVencChnAttr.stVeAttr.enType=enPayLoad;
    if(enPayLoad==PT_H264)//在编码为H264的时候执行，换编码方式在此处
    {
        stH264Attr.u32MaxPicWidth =H264Para.width;
        stH264Attr.u32MaxPicHeight=H264Para.height;
        stH264Attr.u32PicWidth    =H264Para.width;
        stH264Attr.u32PicHeight   =H264Para.height;
        stH264Attr.u32BufSize     =H264Para.width * H264Para.height;//流缓冲器大小
        stH264Attr.u32Profile     =u32Profile;/*0: baseline; 1:MP; 2:HP;  3:svc_t */
        stH264Attr.bByFrame       =HI_TRUE;/*get stream mode is slice mode or frame mode?*/
        stH264Attr.u32BFrameNum   =0;/* 0: not support B frame; >=1: number of B frames */
        stH264Attr.u32RefNum      =1;/* 0: default; number of refrence frame*/
        memcpy(&stVencChnAttr.stVeAttr.stAttrH264e, &stH264Attr, sizeof(VENC_ATTR_H264_S));
        //选择编码码率控制方式——CBR
        {
            stVencChnAttr.stRcAttr.enRcMode=VENC_RC_MODE_H264CBR;
            stH264Cbr.u32Gop         =H264Para.framerate;//图像组：I帧间间隔
            stH264Cbr.u32StatTime    =1; //码率统计时间
            stH264Cbr.u32SrcFrmRate  =30;//输入(VI)帧率
            stH264Cbr.fr32DstFrmRate =H264Para.framerate;//输出帧率
            //下面的定义需要根据传感器修改
            stH264Cbr.u32BitRate     =1024*2;
            stH264Cbr.u32FluctuateLevel=0;//平均比特率
            memcpy(&stVencChnAttr.stRcAttr.stAttrH264Cbr, &stH264Cbr, sizeof(VENC_ATTR_H264_CBR_S));
        }
    }
    
    s32Ret=HI_MPI_VENC_CreateChn(VencChn, &stVencChnAttr);
    if(HI_SUCCESS!=s32Ret)
    {
        OUTPUT("Create VENC Channel[%d] failed! (%#x)\n",VencChn,s32Ret);
        goto END_4;
    }
    
    s32Ret=HI_MPI_VENC_StartRecvPic(VencChn);
    if(HI_SUCCESS!=s32Ret)
    {
        OUTPUT("Start receive VENC picture failed!\n");
        goto END_4;
    }
    
    VpssGrp=0;//选择VPSS组0
    VpssChn=0;//选择VPSS通道0
    VencChn=0;//选择VENC通道0
    stSrcChn.enModId =HI_ID_VPSS;
    stSrcChn.s32DevId=VpssGrp;
    stSrcChn.s32ChnId=VpssChn;
    stDestChn.enModId=HI_ID_VENC;
    stDestChn.s32DevId=0;
    stDestChn.s32ChnId=VencChn;
    s32Ret=HI_MPI_SYS_Bind(&stSrcChn, &stDestChn);
    if(s32Ret!=HI_SUCCESS)
    {
        OUTPUT("Bind VPSS-VENC failed!\n");
        goto END_4;
    }
    /******************************************
    步骤六：VENC流处理——获取流并执行后续操作
    ******************************************/
    VENC_CHN_STAT_S stStat;//通道状态变量
    VENC_STREAM_S stStream;//VENC流
    while(flag_stream_enable)//如果进程运行许可
    {
        s32Ret=HI_MPI_VENC_Query(0, &stStat);
        if(HI_SUCCESS!=s32Ret)
        {
            OUTPUT("Get VENC Query Channel[0] failed!\n");
            break;
        }
        if(0==stStat.u32CurPacks)
        {
            continue;//进入下一轮检测
        }
        
        stStream.pstPack=(VENC_PACK_S*)malloc(sizeof(VENC_PACK_S) * stStat.u32CurPacks);
        if(NULL==stStream.pstPack)
        {
            OUTPUT("Malloc stream pack failed!\n");
            break;
        }
        
        stStream.u32PackCount=stStat.u32CurPacks;
        s32Ret=HI_MPI_VENC_GetStream(0, &stStream, HI_TRUE);
        if(HI_SUCCESS!=s32Ret)
        {
            free(stStream.pstPack);
            stStream.pstPack=NULL;
            OUTPUT("Get VENC Stream failed with %#x!\n",s32Ret);
            break;
        }
        
        HI_U8 *pstream;
        HI_S32 packagelength;
        for(int i=0;i<stStream.u32PackCount;i++)
        {
            pstream = stStream.pstPack[i].pu8Addr + stStream.pstPack[i].u32Offset;
            packagelength = stStream.pstPack[i].u32Len - stStream.pstPack[i].u32Offset;
            
            if(pstream_proc != NULL)
            {
                pstream_proc(pstream, packagelength);
            }
        }
        
        HI_MPI_VENC_ReleaseStream(0,&stStream);
        free(stStream.pstPack);
        stStream.pstPack=NULL;
    }
    
    /* 步骤七：退出处理 */
    //——停止获取VENC流
END_4://VENC部分去初始化操作
    VpssGrp=0;
    VpssChn=0;
    VencChn=0;
    stSrcChn.enModId=HI_ID_VPSS;
    stSrcChn.s32DevId=VpssGrp;
    stSrcChn.s32ChnId=VpssChn;
    stDestChn.enModId=HI_ID_VENC;
    stDestChn.s32DevId=0;
    stDestChn.s32ChnId=VencChn;
    HI_MPI_SYS_UnBind(&stSrcChn, &stDestChn);
    HI_MPI_VENC_StopRecvPic(VencChn);
    HI_MPI_VENC_DestroyChn(VencChn);
END_3:
    stSrcChn.enModId=HI_ID_VIU;
    stSrcChn.s32DevId=0;
    stSrcChn.s32ChnId=0;
    stDestChn.enModId=HI_ID_VPSS;
    stDestChn.s32DevId=VpssGrp;
    stDestChn.s32ChnId=0;
    HI_MPI_SYS_UnBind(&stSrcChn, &stDestChn);
END_2://VPSS去初始化操作
    HI_MPI_VPSS_DisableChn(VpssGrp, VpssChn);
    HI_MPI_VPSS_StopGrp(VpssGrp);
    HI_MPI_VPSS_DestroyGrp(VpssGrp);
END_1://VI部分去初始化操作
    ViDev=0;
    ViChn=0;
    HI_MPI_VI_DisableChn(ViChn);
    HI_MPI_VI_DisableDev(ViDev);
    //停止ISP
    if(gbIspInited)//如果ISP确实初始化了，说明后面的初始化任务可能开始了，执行反注册
    {
        HI_MPI_ISP_Exit(IspDev);//退出MPI ISP系统
        if(gs_IspPid)
        {
            pthread_join(gs_IspPid, 0);
            gs_IspPid=0;
        }
        gbIspInited=HI_FALSE;
        
        /*反注册海思AF库*/
        stLib.s32Id=0;
        strcpy(stLib.acLibName, HI_AF_LIB_NAME);
        HI_MPI_AF_UnRegister(IspDev, &stLib);//AF库反注册

        /*反注册海思AWB库*/
        stLib.s32Id=0;
        strcpy(stLib.acLibName, HI_AWB_LIB_NAME);
        HI_MPI_AWB_UnRegister(IspDev, &stLib);//AWB库反注册

        /*反注册海思AE库*/
        stLib.s32Id=0;
        strcpy(stLib.acLibName, HI_AE_LIB_NAME);
        HI_MPI_AE_UnRegister(IspDev, &stLib);//AE库反注册

        /*传感器反注册回调函数*/
        sensor_unregister_callback();
    }
END_0://系统退出操作
    HI_MPI_SYS_Exit();
    HI_MPI_VB_Exit();
    pthread_exit(NULL);
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：Stream_Start
//|  功能描述：编码线程启动函数
//|  参数说明：无
//|  返回值说明：成功返回0
//|  备注：
//+------------------------------------------------------------------------------------------+
int Stream_Start(void (*pstream_proc_handle)(uint8_t *pstream, int stream_len))
{
    if(flag_stream_start==0)
    {
        flag_stream_enable=1;
        pstream_proc = pstream_proc_handle;
        if(pthread_create(&pthread_t_stream,NULL,stream_process,NULL)==0)
        {
            flag_stream_start=1;
            OUTPUT("Stream thread created.\n");
        }
        else
        {
            OUTPUT("Stream thread created failed!\n");
            goto QUIT;
        }
    }
    
    return 0;

QUIT:
    return -1;
}

//+------------------------------------------------------------------------------------------+
//|  函数名称：Stream_Exit
//|  功能描述：编码线程退出函数
//|  参数说明：无
//|  返回值说明：无
//|  备注：
//+------------------------------------------------------------------------------------------+
void Stream_Exit(void)
{
    if(flag_stream_start)//判断线程存在
    {
        flag_stream_enable=0;//取消线程循环许可标志
        if(pthread_join(pthread_t_stream,0)==0)
        {
            flag_stream_start=0;//指示线程运行结束
        }
    }
}
